﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.Xml.Serialization;
using System.Xml;
using System.IO;
using CRMAdminDashboard.CrmSvc;

namespace CRMAdminDashboard
{
    /// <summary>
    /// Wrapper for CrmSvc.userquery.
    /// </summary>
    public class UserQuery
    {

        #region Properties

        /// <summary>
        /// UserQuery's Guid in CRM.
        /// </summary>
        public Guid Id { get; set; }

        /// <summary>
        /// UserQuery's Name in CRM.
        /// </summary>
        public string Name { get; set; }

        /// <summary>
        /// UserQuery's State in CRM.
        /// </summary>
        public UserQueryState StateCode { get; set; }

        /// <summary>
        /// UserQuery's QueryType in CRM.
        /// </summary>
        public int QueryType { get; set; }

        /// <summary>
        /// Minimum set of attributes to query.
        /// </summary>
        static public ColumnSet UserQueryColumnSet { get; set; }

        /// <summary>
        /// The actual CRM object.
        /// </summary>
        public userquery InnerUserQuery;

        #endregion

        #region Entry Points

        /// <summary>
        /// Standard ctor.
        /// </summary>
        public UserQuery(userquery crmUq)
        {
            this.InnerUserQuery = crmUq;
            this.Name = crmUq.name;
            this.QueryType = crmUq.querytype.Value;
            this.Id = crmUq.userqueryid.Value;
            this.StateCode = crmUq.statecode.Value;
        }

        /// <summary>
        /// This will make the list box entry look nice
        /// </summary>
        public override string ToString()
        {
            switch (HelperManageViews.QueryPrintFormat)
            {
                default:
                    return string.Format("[{0}] {1} [{2}]",
                        SavedQueryType.MnemonicThreeChar[(ushort)this.QueryType],
                        this.Name,
                        this.StateCode == UserQueryState.Active ? "ACTIVE" : "INACTIVE");

                case 1:
                    return this.Name;

                case 2:
                    return string.Format("[{0}] {1}",
                        SavedQueryType.MnemonicThreeChar[(ushort)this.QueryType],
                        this.Name);

                case 3:
                    return string.Format("[{0}] {1}",
                        this.StateCode == UserQueryState.Active ? "ACTIVE" : "INACTIVE",
                        this.Name);
            }
        }

        /// <summary>
        /// Get all source views by user
        /// </summary>
        public static Dictionary<Guid, UserQuery> GetViewsByUser(CachingCrmService svcHandle, SystemUser user, ColumnSetBase columns)
        {
            QueryByAttribute query = new QueryByAttribute();
            query.EntityName = EntityName.userquery.ToString();
            query.ColumnSet = columns;
            query.Attributes = new string[] { "ownerid" };
            query.Values = new object[] { user.Id };

            // impersonate
            Guid originalCaller = svcHandle.CrmAuthenticationTokenValue.CallerId;
            try
            {
                svcHandle.CrmAuthenticationTokenValue.CallerId = user.Id;

                BusinessEntityCollection views = svcHandle.RetrieveMultiple(query);

                Dictionary<Guid, UserQuery> lst = new Dictionary<Guid, UserQuery>();
                foreach (BusinessEntity be in views.BusinessEntities)
                {
                    userquery uq = (userquery)be;
                    lst.Add(uq.userqueryid.Value, new UserQuery(uq));
                }

                return lst;
            }
            finally
            {
                svcHandle.CrmAuthenticationTokenValue.CallerId = originalCaller;
            }
        }

        /// <summary>
        /// Get source views by user, filtered by selectedQueryTypes
        /// </summary>
        public static Dictionary<Guid, UserQuery> GetViewsByUser(CachingCrmService svcHandle, uint selectedQueryTypes, SystemUser user, ColumnSetBase columns)
        {
            Dictionary<Guid, UserQuery> list = GetViewsByUser(svcHandle, user, columns);
            Dictionary<Guid, UserQuery> list2 = new Dictionary<Guid, UserQuery>();

            foreach (UserQuery uq in list.Values)
            {
                if (SavedQueryType.IsQuerySelected(uq, selectedQueryTypes))
                {
                    list2.Add(uq.Id, uq);
                }
            }

            return list2;
        }

        /// <summary>
        /// Get specific source views by user
        /// </summary>
        /// <param name="viewIds">Guid of the views to fetch</param>
        public static Dictionary<Guid, UserQuery> GetViewsByUser(CachingCrmService svcHandle, Guid userId,
            object[] viewIds, ColumnSetBase columns)
        {
            ConditionExpression condition = new ConditionExpression();
            condition.AttributeName = "userqueryid";
            condition.Operator = ConditionOperator.In;
            condition.Values = viewIds;

            FilterExpression filter = new FilterExpression();
            filter.Conditions = new ConditionExpression[] { condition };

            QueryExpression query = new QueryExpression();
            query.EntityName = EntityName.userquery.ToString();
            query.ColumnSet = columns;
            query.Criteria = filter;

            // impersonate
            Guid originalCaller = svcHandle.CrmAuthenticationTokenValue.CallerId;
            try
            {
                svcHandle.CrmAuthenticationTokenValue.CallerId = userId;

                BusinessEntityCollection views = svcHandle.RetrieveMultiple(query);

                Dictionary<Guid, UserQuery> lst = new Dictionary<Guid, UserQuery>();
                foreach (BusinessEntity be in views.BusinessEntities)
                {
                    userquery uq = (userquery)be;
                    lst.Add(uq.userqueryid.Value, new UserQuery(uq));
                }

                return lst;
            }
            finally
            {
                svcHandle.CrmAuthenticationTokenValue.CallerId = originalCaller;
            }
        }

        /// <summary>
        /// Create a shallow copy of InnerUserQuery
        /// </summary>
        public userquery CloneInner()
        {
            userquery cloned = new userquery();

            cloned.columnsetxml = this.InnerUserQuery.columnsetxml;
            cloned.description = this.InnerUserQuery.description;
            cloned.fetchxml = this.InnerUserQuery.fetchxml;
            cloned.layoutxml = this.InnerUserQuery.layoutxml;
            cloned.name = this.InnerUserQuery.name;
            cloned.querytype = this.InnerUserQuery.querytype;
            cloned.returnedtypecode = this.InnerUserQuery.returnedtypecode;
            cloned.createdby = this.InnerUserQuery.createdby;
            cloned.createdon = this.InnerUserQuery.createdon;
            cloned.modifiedby = this.InnerUserQuery.modifiedby;
            cloned.modifiedon = this.InnerUserQuery.modifiedon;
            cloned.ownerid = this.InnerUserQuery.ownerid;
            cloned.owningbusinessunit = this.InnerUserQuery.owningbusinessunit;
            cloned.statecode = this.InnerUserQuery.statecode;
            cloned.statuscode = this.InnerUserQuery.statuscode;
            cloned.userqueryid = this.InnerUserQuery.userqueryid;

            return cloned;
        }

        #endregion

        #region Local Methods

        /// <summary>
        /// Static initializer
        /// </summary>
        static UserQuery()
        {
            UserQueryColumnSet = new ColumnSet();
            UserQueryColumnSet.Attributes = new string[] { "name", "querytype", "statecode" };
        }

        #endregion

    }
}
